package com.yxw.yxnet_cd_center.customer_service.service.impl;

import com.yxw.yxnet_cd_center.customer_service.utils.RedisManager;
import com.yxw.yxnet_cd_center.customer_service.utils.UserUtil;
import com.yxw.yxnet_cd_center.customer_service.utils.JwtUtil;
import com.yxw.yxnet_cd_center.customer_service.utils.JsonUtils;
import com.yxw.yxnet_cd_center.customer_service.utils.HuaWeiSmsUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yxw.yxnet_cd_center.common.constant.CommonConstant;
import com.yxw.yxnet_cd_center.common.constant.MqttPrefixConstant;
import com.yxw.yxnet_cd_center.common.constant.RedisIdConstant;
import com.yxw.yxnet_cd_center.common.dto.BaseDTO;
import com.yxw.yxnet_cd_center.common.dto.HuaWeiSmsDTO;
import com.yxw.yxnet_cd_center.common.enums.CommonErrorEnum;
import com.yxw.yxnet_cd_center.common.enums.NoticeTypeEnum;
import com.yxw.yxnet_cd_center.common.exception.BaseException;
import com.yxw.yxnet_cd_center.common.result.TokenInfo;
import com.yxw.yxnet_cd_center.common.utils.PasswordUtil;
import com.yxw.yxnet_cd_center.common.utils.TokenUtil;
import com.yxw.yxnet_cd_center.customer_service.dto.UserLoginDTO;
import com.yxw.yxnet_cd_center.customer_service.dto.UserPhoneLoginDTO;
import com.yxw.yxnet_cd_center.customer_service.dto.UserSendCodeDTO;
import com.yxw.yxnet_cd_center.customer_service.entity.YxCsSmsTemplateEntity;
import com.yxw.yxnet_cd_center.customer_service.entity.YxCsUserEntity;
import com.yxw.yxnet_cd_center.customer_service.exception.RrException;
import com.yxw.yxnet_cd_center.customer_service.mapper.SmsTemplateMapper;
import com.yxw.yxnet_cd_center.customer_service.mapper.UserMapper;
import com.yxw.yxnet_cd_center.customer_service.mqtt.MqttGateway;
import com.yxw.yxnet_cd_center.customer_service.service.LoginService;
import com.yxw.yxnet_cd_center.customer_service.vo.LoginUserVo;
import com.yxw.yxnet_cd_center.customer_service.vo.MqttInforSystemVO;
import com.yxw.yxnet_cd_center.customer_service.vo.UserInfoVo;
import com.yxw.yxnet_cd_center.customer_service.vo.UserTokenVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Objects;

/**
 * 登录管理
 * @author liuxin
 * @date 2023.09.12
 */
@Service
public class LoginServiceImpl extends ServiceImpl<UserMapper, YxCsUserEntity> implements LoginService {

    @Resource
    private RedisManager redisManager;

    @Autowired
    private UserUtil userUtil;

    @Resource
    private HuaWeiSmsUtil smsComponent;

    @Autowired
    private SmsTemplateMapper smsTemplateMapper;

    @Autowired
    private MqttGateway mqttGateway;

    /**
     * 登出
     * @param baseDTO
     */
    @Override
    public void logout(BaseDTO baseDTO) {
        UserTokenVo userTokenVo = (UserTokenVo) redisManager.get(RedisIdConstant.LOGIN_TOKEN + userUtil.getLoginUserId());
        if(userTokenVo != null) {
            redisManager.del(RedisIdConstant.LOGIN_TOKEN + userUtil.getLoginUserId());
//            Object obj = redisManager.get("CSS_POWER_PC_" + userUtil.getLoginUserId());
//            List<String> permissionList = ObjectToListUtil.castList(obj, String.class);
//            if(permissionList.size() > 0) {
//                redisManager.del("CSS_POWER_PC_" + userUtil.getLoginUserId());
//            }
        }
        //修改登陆状态
        YxCsUserEntity user = baseMapper.selectById(userUtil.getLoginUserId());
        if(null!=user){
            user.setLoginStatus(0);
            user.setLastLoginTime(user.getLoginTime());
            user.setLoginTime(null);
            baseMapper.updateById(user);
        }
    }

    /**
     * 账号密码登录
     * @param userLoginDTO
     * @return
     */
    @Override
    public LoginUserVo login(UserLoginDTO userLoginDTO){
        //用户信息
        YxCsUserEntity user = baseMapper.selectOne(new LambdaQueryWrapper<YxCsUserEntity>()
                .eq(YxCsUserEntity::getUserNum, userLoginDTO.getUserNum())
                .eq(YxCsUserEntity::getUserStatus, 0)
        );
        //账号不存在、密码错误
        if(user == null || !Objects.equals(PasswordUtil.signUserPassword(user.getUserId(),userLoginDTO.getPassword()), user.getPassword())) {
            throw new BaseException("账号或密码不正确");
        }
        //发送异地登录提醒,下线已登录账号
        this.sendOfflineNotice(user);
        LoginUserVo loginUserVo = getLoginUserVo(user);
        //修改登录状态
        user.setLoginStatus(1);
        user.setLoginTime(LocalDateTime.now());
        baseMapper.updateById(user);
        return loginUserVo;
    }

    @Override
    public LoginUserVo phone(UserPhoneLoginDTO userPhoneLoginDTO) {
        YxCsUserEntity user = baseMapper.selectOne(new LambdaQueryWrapper<YxCsUserEntity>()
                .eq(YxCsUserEntity::getMobilePhone, userPhoneLoginDTO.getMobilePhone())
                .eq(YxCsUserEntity::getUserStatus, 0)
        );
        if(user == null) {
            throw new RrException("账号不存在");
        }
        String code = (String) redisManager.get(RedisIdConstant.LOGIN_SMS_CODE + userPhoneLoginDTO.getMobilePhone());
        if(!userPhoneLoginDTO.getCode().equals(code)){
            throw new BaseException("手机验证码错误");
        }
        //发送异地登录提醒,下线已登录账号
        this.sendOfflineNotice(user);
        LoginUserVo loginUserVo = getLoginUserVo(user);
        //修改登录状态
        user.setLoginStatus(1);
        user.setLoginTime(LocalDateTime.now());
        baseMapper.updateById(user);
        return loginUserVo;
    }

    /**
     *
     * @param userSendCodeDTO
     */
    @Override
    public void send(UserSendCodeDTO userSendCodeDTO) {
        String code = RandomUtil.randomNumbers(6);
        redisManager.set(RedisIdConstant.LOGIN_SMS_CODE + userSendCodeDTO.getPhone(), code, 5 * 60);
        //查询模板配置
        LambdaQueryWrapper<YxCsSmsTemplateEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(YxCsSmsTemplateEntity::getTemplateCode, NoticeTypeEnum.SMS_CODE.getTemplateCode());
        YxCsSmsTemplateEntity entity = smsTemplateMapper.selectOne(wrapper);
        if(null==entity){
            throw new BaseException("短信模板未配置");
        }
        HuaWeiSmsDTO dto=new HuaWeiSmsDTO();
        dto.setTemplateParas("[\"" + code +"\"]");
        dto.setPhone(userSendCodeDTO.getPhone());
        dto.setSender(entity.getSender());
        dto.setTemplateId(entity.getHwTemplateId());
        smsComponent.sendSmsCode(dto);
    }

    /**
     * 刷新token接口
     * @param request
     * @return
     */
    @Override
    public LoginUserVo refreshToken(HttpServletRequest request) {
        //获取请求头token信息
        Cookie[] cookies = request.getCookies();
        if(null==cookies || cookies.length==0){
            throw new BaseException(CommonErrorEnum.REQUEST_HEADER_GET_TOKEN_EXCEPTION);
        }
        String token="";
        for (Cookie cookie:cookies) {
            if(CommonConstant.TOKEN.equals(cookie.getName())){
                token=cookie.getValue();
            }
        }
        if(StringUtils.isBlank(token)){
            throw new BaseException(CommonErrorEnum.REQUEST_HEADER_GET_TOKEN_EXCEPTION);
        }
        //解析token
        TokenInfo tokenInfo = TokenUtil.getTokenInfoByToken(token);
        Long userId = tokenInfo.getUserId();
        YxCsUserEntity user = baseMapper.selectOne(new LambdaQueryWrapper<YxCsUserEntity>()
                .eq(YxCsUserEntity::getUserId, userId)
                .eq(YxCsUserEntity::getUserStatus, 0)
        );
        if(null==user){
            throw new BaseException(CommonErrorEnum.VERIFY_USER_TOKEN_EXCEPTION);
        }
        return getLoginUserVo(user);
    }

    //-------------------------------------------------------------------------------------------------------------------------------------------------
    private LoginUserVo getLoginUserVo(YxCsUserEntity user) {
        LoginUserVo loginUserVo = new LoginUserVo();
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtil.copyProperties(user, userInfoVo);
        long checkCode = System.currentTimeMillis();
        UserTokenVo userTokenVo = new UserTokenVo();
        BeanUtil.copyProperties(user, userTokenVo);
        userTokenVo.setCheckCode(checkCode);
        userTokenVo.setExpirationDate(LocalDateTime.now().plusMinutes(30));
        String token = JwtUtil.generateToken(userTokenVo, checkCode);
        loginUserVo.setUser(userInfoVo);
        loginUserVo.setToken(token);
        UserTokenVo tokenVo = (UserTokenVo) redisManager.get(RedisIdConstant.LOGIN_TOKEN + user.getUserId());
        if(tokenVo != null) {
            redisManager.del(RedisIdConstant.LOGIN_TOKEN + user.getUserId());
        }
        redisManager.set(RedisIdConstant.LOGIN_TOKEN + user.getUserId(), userTokenVo, 60 * 60);
        return loginUserVo;
    }

    /**
     * 发送用户下线通知
     */
    private void sendOfflineNotice(YxCsUserEntity user) {
        MqttInforSystemVO systemVO = new MqttInforSystemVO();
        systemVO.setContent("该账号在别的地方登录,如非本人操作,请尽快修改登录密码");
        systemVO.setMsgType("sys");
        systemVO.setContentType("offline");
        systemVO.setRecv(String.valueOf(user.getId()));
        //下线操作
        systemVO.setNotificationType("offline");
        mqttGateway.sendToMqtt(MqttPrefixConstant.SYSTEM_SYSTEM_MQTT_TOPIC_PREFIX + user.getId(), JsonUtils.toJson(systemVO));
    }
}
